﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Caching;
using System.Web.Mvc;
using CkSoftware.GroupMe.Sdk.Bot;
using CkSoftware.GroupMe.Sdk.Core.Dao;
using CkSoftware.GroupMe.Sdk.TestWeb.Helpers;
using CkSoftware.GroupMe.Sdk.TestWeb.Models;

namespace CkSoftware.GroupMe.Sdk.TestWeb.Controllers
{
	public class BotController : Controller
	{
		private readonly GroupMeBotCallbackHandler _callbackHandler = new GroupMeBotCallbackHandler();

		public ActionResult Index()
		{
			var model = new BotConfigurationModel
				{
					ApiKey = SessionConfiguration.GetConfigValue<string>(SessionConfiguration.GroupMeBotApiKeyConfigKey),
					GroupMeGroupId = SessionConfiguration.GetConfigValue<string>(SessionConfiguration.GroupMeGroupIdConfigKey)
				};

			return View(model);
		}

		public async Task<ActionResult> IndexAllBots()
		{
			var model = new IndexAllBotsModel
				{
					Bots = await BotHelper.GetAllBots()
				};

			return View(model);
		}

		public ActionResult Configure(BotConfigurationModel model)
		{
			SessionConfiguration.SetConfigValue(SessionConfiguration.GroupMeBotApiKeyConfigKey, model.ApiKey);

			return RedirectToAction("Index");
		}

		public async Task<ActionResult> StartBot(BotConfigurationModel model)
		{
			if (ModelState.IsValid)
			{
				SessionConfiguration.SetConfigValue(SessionConfiguration.GroupMeGroupIdConfigKey, model.GroupMeGroupId);
				string callbackUrl = string.Empty;
				if (model.RegisterCallback && Request.Url != null)
				{
					SessionConfiguration.SetConfigValue(SessionConfiguration.CallbackGroupId, model.GroupMeGroupId);
					callbackUrl = Url.Action("BotCallback", "Bot", null, Request.Url.Scheme, Request.Url.Host);
				}

				await BotHelper.StartBot(model.BotName, model.AvatarUrl, callbackUrl);
				return RedirectToAction("Index");
			}

			return View("Index", model);
		}

		public async Task<ActionResult> DestroyBot()
		{
			await BotHelper.DestroyBot();
			return RedirectToAction("Index");
		}

		public async Task<ActionResult> SendMessage(string message, string attachmentImageUrl)
		{
			await BotHelper.SendMessage(message, attachmentImageUrl);
			return RedirectToAction("Index");
		}

		public ActionResult ListCallbackMessages()
		{
			var model = Enumerable.Empty<GroupMeMessageData>();
			var callbackGroupId = SessionConfiguration.GetConfigValue<string>(SessionConfiguration.CallbackGroupId);

			if (!string.IsNullOrEmpty(callbackGroupId))
			{
				var cacheKey = GenerateCacheKeyForGroupId(callbackGroupId);
				var data = HttpContext.Cache.Get(cacheKey) as List<GroupMeMessageData> ?? Enumerable.Empty<GroupMeMessageData>();

				model = data;
			}

			return View(model);
		}

		public async Task<ActionResult> DestroyBotById(string botId)
		{
			await BotHelper.DestroyBotWithId(botId);
			return RedirectToAction("IndexAllBots");
		}

		public async Task<ActionResult> UseBotWithId(string botId)
		{
			await BotHelper.SetBotWithIdAsCurrentBot(botId);
			return RedirectToAction("Index");
		}

		[HttpPost]
		public ActionResult BotCallback()
		{
			string postData;
			using (var reader = new StreamReader(Request.InputStream))
			{
				postData = reader.ReadToEnd();
			}

			if (!string.IsNullOrEmpty(postData))
			{
				var botMessage = _callbackHandler.Parse(postData);

				if (botMessage != null)
				{
					var cacheKey = GenerateCacheKeyForGroupId(botMessage.GroupId);
					var currentGroupData = HttpContext.Cache.Get(cacheKey) as List<GroupMeMessageData> ??
					                       new List<GroupMeMessageData>();

					currentGroupData.Add(botMessage);

					HttpContext.Cache.Add(
						cacheKey,
						currentGroupData,
						null,
						Cache.NoAbsoluteExpiration,
						TimeSpan.FromMinutes(20),
						CacheItemPriority.Default,
						null);
				}
			}

			return new EmptyResult();
		}

		private string GenerateCacheKeyForGroupId(string groupId)
		{
			return string.Concat("Callbacks_", groupId);
		}
	}
}